package net.imagine.provider.skyline;

import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;

import net.imagine.core.ImageInfo;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Skyline 中使用的一些策略
 * 
 * @author wuqh
 * */
public class SkylineImagineUtils {
	private static final Log logger = LogFactory.getLog(SkylineImagineUtils.class);
	public static final String DEFAULT_EXT = "png";

	/**
	 * 基于把一个同名的文件传到统一相册，且这几个服务器上时间戳加nanoTime还恰巧一样
	 * 根据用户ID，相册id，源文件名生成文件名，MD5(userId-albumId-源文件名-dateTime-nanoTime)
	 * 这样时间大约是使用UUID的1/3
	 * 
	 * @param args [userId,albumId,filename]
	 * 
	 * @return 文件名
	 */
	public static String generateFileKey(String... args) {
		int length = args.length;
		if (length != 3) {
			logger.warn("args length != 3");
			throw new RuntimeException("args length != 3");
		}
		String userId = args[0];
		String albumId = args[1];
		String filename = args[2];
		long dateTime = (new Date()).getTime();
		long nanoTime = System.nanoTime();
		String data = userId + '-' + albumId + '-' + filename + '-' + dateTime + '-' + nanoTime;
		String fileKey = DigestUtils.md5Hex(data);
		if (logger.isDebugEnabled()) {
			logger.debug("key:" + fileKey + " is generated");
		}
		return fileKey;
	}

	/**
	 * 根据基本基本路径，用户ID，相册id，源文件名生成目录（带文件名）
	 * */
	public static String generateFilePath(String basePath, long userId, long albumId, String filename) {
		return generateFilePath(basePath, userId, albumId) + filename;
	}

	/**
	 * 根据基本基本路径，用户ID，相册id，生成目录
	 * */
	public static String generateFilePath(String basePath, long userId, long albumId) {
		long shortId = userId % 1000;
		return basePath + '/' + shortId + '/' + userId + '/' + albumId + '/';
	}

	/**
	 * GraphicsMagick中使用，identify 命令获取图片信息后解析，看图片是否为制定格式，如果是返回图片信息 否则返回空 <br/>
	 * 图片信息格式如下：文件名 格式 宽度x高度+......，其中文件名可能为文件名[0]（如果为多帧） 以此获取图片信息
	 * 
	 * @param info
	 *            GraphicsMagick中使用，identify 命令获取图片信息
	 * @param ext
	 *            指定的图片格式，看图片信息中是否包涵该格式
	 * */
	public static ImageInfo parseImageInfo(String info, String ext) {
		int index = info.indexOf(ext);
		if (index == -1) {
			return null;
		}
		int indexOfSpace = info.indexOf(" ", index);
		int indexOfX = info.indexOf("x", indexOfSpace);
		int indexOfPlus = info.indexOf("+", indexOfX);
		String width = info.substring(indexOfSpace + 1, indexOfX);
		String height = info.substring(indexOfX + 1, indexOfPlus);

		if ("JPEG".equals(ext)) { // 对于JPG文件解析的文件格式为JPEG,需要做一次转换
			ext = "JPG";
		}

		if (logger.isDebugEnabled())
			logger.debug("image format:" + ext + ",width:" + width + ",height:" + height);

		ImageInfo imageInfo = new ImageInfo();
		imageInfo.setExt(ext.toLowerCase());
		imageInfo.setHeight(Integer.parseInt(height));
		imageInfo.setWidth(Integer.parseInt(width));
		return imageInfo;
	}
	
	/***
	 * 通过路径对应图片的扩展名判断是否为多帧
	 * 
	 * @param srcURL 图片路径（必须带有扩展名）
	 * */
	public static boolean hasMultiFrame(String srcURL) {
		String ext = FilenameUtils.getExtension(srcURL);
		return isExtMultiFrame(ext);
	}
	
	/***
	 * 判断扩展名是否为多帧
	 * 
	 * @param ext 扩展名
	 * */
	public static boolean isExtMultiFrame(String ext) {
		return "GIF".equalsIgnoreCase(ext);
	}

	/**
	 * 关闭输入输出流
	 * 
	 * @param stream
	 *            流
	 * */
	public static void closeStream(Closeable stream) {
		if (stream == null) {
			return;
		}
		try {
			stream.close();
		} catch (IOException e) {
			logger.warn("an IOException occurred while close the stream", e);
		}
	}
	
	public static void writeStreamToFile(File file, InputStream input) throws IOException {
		OutputStream output = null;
		try {
			output = new FileOutputStream(file);
			IOUtils.copy(input, output);
		} catch (IOException e) {
			throw e;
		} finally {
			closeStream(input);
			closeStream(output);
		}
	}
}
